package Sync
{
	import Common.Deleter;
	
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.Socket;
	import flash.utils.*;
		
	public class SyncSystemBase
	{	
		
		public function SyncSystemBase()
		{
			socket = new Socket();
			socket.addEventListener(Event.CLOSE, __onCloseHandler);
			socket.addEventListener(IOErrorEvent.IO_ERROR, __onIOError);
			socket.addEventListener(Event.CONNECT, __onConnectHandler);
			socket.addEventListener(ProgressEvent.SOCKET_DATA, __onReceiveData);
			socket.endian =  Endian.LITTLE_ENDIAN;
			
			listeners= new Array();
			listeners.push( new Room);
			
			buffer = new ByteArray();
			buffer.endian = Endian.LITTLE_ENDIAN;
			stream = new Stream();
			stream.setByteArray(buffer);
			
			receiveBuff = new ByteArray();
			receiveBuff.endian = Endian.LITTLE_ENDIAN;
			receiverStream = new Stream();
			receiverStream.setByteArray(receiveBuff);
		}
		
		public function isConnected():Boolean
		{
			return socket.connected;
		}
		
		public function connectToServer(host:String, port:int):void
		{
			socket.connect(host, port);
		}
		
		public function addListener(listener:IListener):void
		{
			listeners.push(listener);
		}
		
		public function removeListener(listener:IListener):void
		{
			var index:int = listeners.indexOf(listener);
			if (index != -1)
			{
				listeners.splice(index, 1);
			}
		}
		
		public function beginSendMsg(msgID:uint):Stream
		{
			if (locked)
			{
				throw "error";
			}
			
			locked = true;
			
			buffer.writeShort(ConstValue.zeroPackageSize);//占位符
			stream.writeInt(msgID);
			return stream;
		}
		
		public function endSendMsg():Boolean
		{
			if (!locked)
			{
				throw "error";
			}
			
			locked = false;
			
			if (socket.connected == false)
			{
				buffer.clear();
				return false;
			}
			
			var len:int = buffer.position;
			buffer.position = 0;
			buffer.writeShort(buffer.length - 2);
			buffer.position = len;
			
			socket.writeBytes(buffer);
			socket.flush();
			buffer.clear();
			
			return true;
		}
		
		public function step():void
		{
			for(var i:uint = 0; i < listeners.length; i++)
			{
				for (var count:int = 0; count < numPerStep; ++count)
				{
					listeners[i].step();
				}
			}
		}
		
		public function release():void
		{
			Deleter(socket);
			Deleter(listeners);
			Deleter(buffer);
			Deleter(stream);
			Deleter(receiveBuff);
			Deleter(receiverStream);
			
			for(var i:uint = 0; i < listeners.length; i++)
			{
				listeners[i].release();
			}
		}
		
		private function __onCloseHandler(e:Event):void
		{
			for(var i:uint = 0; i < listeners.length; i++)
			{
				listeners[i].onServerClosed();
			}
		}
		
		private function __onIOError(e:Event):void
		{
			for(var i:uint = 0; i < listeners.length; i++)
			{
				listeners[i].onSocketError();
			}
		}
		
		
		private function __onConnectHandler(e:Event):void
		{
			for(var i:uint = 0; i < listeners.length; i++)
			{
				listeners[i].onServerConnected();
			}
		}
		
		private var lastTime:int = 0;
		
		private function __onReceiveData(e:ProgressEvent):void
		{
			trace("receive socket data size: " + socket.bytesAvailable + "  time: " + getTimer());
			
			socket.readBytes(receiveBuff, receiveBuff.length, socket.bytesAvailable);
			
			while (receiveBuff.bytesAvailable > 2)
			{
				var packetSize:int = receiveBuff.readShort();
				
				if (receiveBuff.bytesAvailable >= packetSize)
				{
					var nextPos:int = receiveBuff.position + packetSize;
					var packetPos:int = receiveBuff.position;
					
					var packet:ByteArray = new ByteArray();
					packet.endian = Endian.LITTLE_ENDIAN;
					
					receiveBuff.readBytes(packet, 0, packetSize);
					
					receiverStream.setByteArray(packet);
				
					for(var i:uint = 0; i < listeners.length; i++)
					{
						listeners[i].onServerMessage(receiverStream);
						
						packet.position = 0;
					}
					
					receiveBuff.position = nextPos;
					
					trace("packet");
				}
				else
				{
					receiveBuff.position = receiveBuff.position - 2;
					break;
				}
			}
			
			if (receiveBuff.bytesAvailable == 0)
				receiveBuff.clear();
		}
		
		public function setNumPerStep(num:int):void
		{
			numPerStep = num;
		}
		
		
		
		private var socket:Socket = null;
		private var listeners:Array = null;
		private var receiveBuff:ByteArray = null;
		private var receiverStream:Stream = null;
		private var locked:Boolean = false;
		protected var stream:Stream = null;
		protected var buffer:ByteArray = null;
		
		private var numPerStep:int = 1;
	}
}